﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;


namespace EssenceFeed.Core.Helpers
{
    /// <summary>
    /// HtmlHelpers
    /// </summary>
    public static class HtmlHelpers
    {
        /// <summary>
        /// This is a simple HTML Helper which truncates a string to a given length
        /// </summary>
        /// <param name="helper">HTML Helper being extended</param>
        /// <param name="input">Input string to truncate</param>
        /// <param name="length">Max length of the string</param>
        /// <returns></returns>
        public static string Truncate(this HtmlHelper helper, string input, int length)
        {
            return input.Length <= length ? input : input.Substring(0, length) + "...";
        }

        ///// <summary>
        ///// DatePicker
        ///// </summary>
        ///// <param name="helper"></param>
        ///// <param name="name"></param>
        ///// <param name="imageUrl"></param>
        ///// <param name="date"></param>
        ///// <returns></returns>
        //public static string DatePicker(this HtmlHelper helper, string name, string imageUrl, object date)
        //{
        //    var html = new StringBuilder();

        //    // Build our base input element
        //    html.Append("<input type=\"text\" id=\"" + name + "\" name=\"" + name + "\"");

        //    // Model Binding Support
        //    if (date != null)
        //    {
        //        string dateValue = String.Empty;

        //        if (date is DateTime? && ((DateTime)date) != DateTime.MinValue)
        //            dateValue = ((DateTime)date).ToShortDateString();
        //        else if (date is DateTime && (DateTime)date != DateTime.MinValue)
        //            dateValue = ((DateTime)date).ToShortDateString();
        //        else if (date is string)
        //            dateValue = (string)date;

        //        html.Append(" value=\"" + dateValue + "\"");
        //    }

        //    // We're hard-coding the width here, a better option would be to pass in html attributes and reflect through them
        //    // here ( default to 75px width if no style attributes )
        //    html.Append(" style=\"width: 75px;\" />");

        //    // Now we call the datepicker function, passing in our options.  Again, a future enhancement would be to
        //    // pass in date options as a list of attributes ( min dates, day/month/year formats, etc. )
        //    html.Append("<script type=\"text/javascript\">$(document).ready(function() { $('#" + name + "').date picker({ showOn: 'button', buttonImage: '" + imageUrl + "', duration: 0 }); });</script>");

        //    return html.ToString();
        //}
        /*
        /// <summary>
        /// Create Delete Link
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="actionName"></param>
        /// <param name="controllerName"></param>
        /// <param name="routeValues"></param>
        /// <param name="imageUrlPath"></param>
        /// <param name="altText"></param>
        /// <returns></returns>
        public static MvcHtmlString CustomActionLink(this HtmlHelper helper, string actionName, string controllerName, object routeValues, string imageUrlPath, string altText)
        {
            var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            var url = urlHelper.Action(actionName, controllerName, routeValues);
  
            var formTag = new TagBuilder("form");
            formTag.MergeAttribute("action", url);
            formTag.MergeAttribute("method", "post");

            var inputTag = new TagBuilder("input");
            inputTag.MergeAttribute("type", "image");
            inputTag.MergeAttribute("src", imageUrlPath);
            inputTag.MergeAttribute("alt", altText);
            inputTag.MergeAttribute("Title",altText);
            formTag.InnerHtml = altText == "Delete"
                                    ? inputTag.ToString(TagRenderMode.SelfClosing) +
                                      helper.HttpMethodOverride(HttpVerbs.Delete)
                                    : inputTag.ToString(TagRenderMode.SelfClosing) +
                                      helper.HttpMethodOverride(HttpVerbs.Put);
            return MvcHtmlString.Create(formTag.ToString());
        }

        */
        /// <summary>
        /// RadioButtonList
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <param name="items"></param>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TProperty"></typeparam>
        /// <returns></returns>
        public static MvcHtmlString RadioButtonList<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, params string[] items)   
        {  
            return htmlHelper.RadioButtonList(expression, new SelectList(items));   
        }

        /// <summary>
        /// RadioButtonList
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <param name="items"></param>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TProperty"></typeparam>
        /// <returns></returns>
        public static MvcHtmlString RadioButtonList<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> items)
        {   
            var func = expression.Compile();  
            var result = func(htmlHelper.ViewData.Model); 
            var list = new SelectList(items, "Value", "Text", result);  
            return htmlHelper.EditorFor(expression, "RadioButtonList", new { selectList = list }); 
        }

        /// <summary>
        /// YesNoDropDownList
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="id"></param>
        /// <param name="selectedValue"></param>
        /// <returns></returns>
        public static MvcHtmlString YesNoDropDownList(this HtmlHelper helper, string id, string selectedValue)
        {

            var list = new SelectList(new[]
                              {
                                  new {text = "Select", value = "0"},
                                  new {text = "No", value = "1"},
                                  new {text = "Yes", value = "2"}
                              }, "value", "text", selectedValue);

            return helper.DropDownList(id, list);
        }

        #region DropdownList

        /// <summary>
        /// Convert the list of strings to a selectListItems.
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="selectedValue"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public static IList<SelectListItem> ToDropDownList(this HtmlHelper helper, string selectedValue, string[] items)
        {
            IList<SelectListItem> selections = new List<SelectListItem>();
            if (items != null)
            {
                foreach (string item in items)
                {
                    bool selected = string.Compare(item, selectedValue) == 0;
                    selections.Add(new SelectListItem() { Selected = selected, Text = item, Value = item });
                }
            }
            return selections;
        }


        /// <summary>
        /// Convert the list of strings to a selectListItems.
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="selectedValue"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public static IList<SelectListItem> ToDropDownList(this HtmlHelper helper, string selectedValue, IList<string> items)
        {
            IList<SelectListItem> selections = new List<SelectListItem>();
            foreach (string item in items)
            {
                bool selected = string.Compare(item, selectedValue) == 0;
                selections.Add(new SelectListItem() { Selected = selected, Text = item, Value = item });
            }
            return selections;
        }
        #endregion

        /// <summary>
        /// Create Drop Down List From Enum
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="name"></param>
        /// <param name="selectedValue"></param>
        /// <typeparam name="TEnum"></typeparam>
        /// <returns></returns>
        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, TEnum selectedValue)
        {
            var values = Enum.GetValues(typeof(TEnum))
                .Cast<TEnum>();

            var items =
                from value in values
                select new SelectListItem
                {
                    Text = value.ToString(),
                    Value = value.ToString(),
                    Selected = (value.Equals(selectedValue))
                };

            return htmlHelper.DropDownList(
                name,
                items
                );
        }

        /// <summary>
        /// Create Drop Down List From Enum
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <typeparam name="TEnum"></typeparam>
        /// <typeparam name="TModel"></typeparam>
        /// <returns></returns>
        public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
        {
            var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            var enumType = getNonNullableModelType(metadata);
            var values = Enum.GetValues(enumType).Cast<TEnum>();

            var items =
                values.Select(value => new SelectListItem
                {
                    Text = value.ToString(),
                    Value = value.ToString(),
                    Selected = value.Equals(metadata.Model)
                });

            if (metadata.IsNullableValueType)
            {
                items = SingleEmptyItem.Concat(items);
            }

            return htmlHelper.DropDownListFor(
                expression,
                items
                );
        }

        private static Type getNonNullableModelType(ModelMetadata modelMetadata)
        {
            var realModelType = modelMetadata.ModelType;

            var underlyingType = Nullable.GetUnderlyingType(realModelType);
            if (underlyingType != null)
            {
                realModelType = underlyingType;
            }
            return realModelType;
        }

        private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } };

        /// <summary>
        /// Paging in MVC
        /// </summary>
        /// <param name="html"></param>
        /// <param name="pagedList"></param>
        /// <param name="url"></param>
        /// <param name="pagePlaceHolder"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        //public static string Paging(this HtmlHelper html, IPagedList<T> pagedList, string url, string pagePlaceHolder)
        //{
        //    if (pagedList == null) throw new ArgumentNullException("pagedList");

        //    var sb = new StringBuilder();

        //    // only show paging if we have more items than the page size
        //    if (pagedList.ItemCount > pagedList.PageSize)
        //    {

        //        sb.Append("<ul class=\"paging\">");

        //        if (pagedList.IsPreviousPage)
        //        { // previous link
        //            sb.Append("<li class=\"prev\"><a href=\"");
        //            sb.Append(url.Replace(pagePlaceHolder, pagedList.PageIndex.ToString()));
        //            sb.Append("\" title=\"Go to Previous Page\">prev</a></li>");
        //        }

        //        for (int i = 0; i < pagedList.PageCount; i++)
        //        {
        //            sb.Append("<li>");
        //            if (i == pagedList.PageIndex)
        //            {
        //                sb.Append("<span>").Append((i + 1).ToString()).Append("</span>");
        //            }
        //            else
        //            {
        //                sb.Append("<a href=\"");
        //                sb.Append(url.Replace(pagePlaceHolder, (i + 1).ToString()));
        //                sb.Append("\" title=\"Go to Page ").Append((i + 1).ToString());
        //                sb.Append("\">").Append((i + 1).ToString()).Append("</a>");
        //            }
        //            sb.Append("</li>");
        //        }

        //        if (pagedList.IsNextPage)
        //        { // next link
        //            sb.Append("<li class=\"next\"><a href=\"");
        //            sb.Append(url.Replace(pagePlaceHolder, (pagedList.PageIndex + 2).ToString()));
        //            sb.Append("\" title=\"Go to Next Page\">next</a></li>");
        //        }

        //        sb.Append("</ul>");
        //    }

        //    return sb.ToString();
        //}
        /*

        /// <summary>
        /// Generate Table
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="name"></param>
        /// <param name="items"></param>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public static string Table(this HtmlHelper helper, string name, IList items, IDictionary<string, object> attributes)
        {
            if (items == null || items.Count == 0 || string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }

            return BuildTable(name, items, attributes);
        }
        
        /// <summary>
        /// Build Table
        /// </summary>
        /// <param name="name"></param>
        /// <param name="items"></param>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public static string BuildTable(string name, IList items, IDictionary<string, object> attributes)
        {
            var sb = new StringBuilder();
            BuildTableHeader(sb, items[0].GetType());

            foreach (var item in items)
            {
                BuildTableRow(sb, item);
            }

            var builder = new TagBuilder("table");
            builder.MergeAttributes(attributes);
            builder.MergeAttribute("name", name);
            builder.InnerHtml = sb.ToString();
            return builder.ToString(TagRenderMode.Normal);
        }

        /// <summary>
        /// Build Table Row
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="obj"></param>
        public static void BuildTableRow(StringBuilder sb, object obj)
        {
            Type objType = obj.GetType();
            sb.AppendLine("\t<tr>");
            foreach (var property in objType.GetProperties())
            {
                sb.AppendFormat("\t\t<td>{0}</td>\n", property.GetValue(obj, null));
            }
            sb.AppendLine("\t</tr>");
        }

        /// <summary>
        /// Build Table Header
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="p"></param>
        public static void BuildTableHeader(StringBuilder sb, Type p)
        {
            sb.AppendLine("\t<tr>");
            foreach (var property in p.GetProperties())
            {
                sb.AppendFormat("\t\t<th>{0}</th>\n", property.Name);
            }
            sb.AppendLine("\t</tr>");
        }

        /// <summary>
        /// Generate Image
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="src"></param>
        /// <param name="alt"></param>
        /// <returns></returns>
        public static string Image(this HtmlHelper helper, string src, string alt)
        {
            var tb = new TagBuilder("img");
            tb.Attributes.Add("src", helper.Encode(src));
            tb.Attributes.Add("alt", helper.Encode(alt));
            return tb.ToString(TagRenderMode.SelfClosing);
        }

        /// <summary>
        /// Create Link for an Image
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="imgSrc"></param>
        /// <param name="alt"></param>
        /// <param name="actionName"></param>
        /// <param name="controllerName"></param>
        /// <param name="routeValues"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="imgHtmlAttributes"></param>
        /// <returns></returns>
        public static string ImageLink(this HtmlHelper htmlHelper, string imgSrc, string alt, string actionName, string controllerName, object routeValues, object htmlAttributes, object imgHtmlAttributes)
        {
            var urlHelper = ((Controller)htmlHelper.ViewContext.Controller).Url;
            var imgTag = new TagBuilder("img");
            imgTag.MergeAttribute("src", imgSrc);
            imgTag.MergeAttributes((IDictionary<string, string>)imgHtmlAttributes, true);
            var url = urlHelper.Action(actionName, controllerName, routeValues);

            var imglink = new TagBuilder("a");
            imglink.MergeAttribute("href", url);
            imglink.InnerHtml = imgTag.ToString();
            imglink.MergeAttributes((IDictionary<string, string>)htmlAttributes, true);

            return imglink.ToString();
        }

        /// <summary>
        /// Delete Confirmation Box
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="controller"></param>
        /// <param name="action"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static string DeleteForm(this HtmlHelper helper, string controller, string action, int id)
        {
            //if (helper != null)
            //{
            //    var url = new UrlHelper(helper.ViewContext);
            //    var postAction = url.Action(action, controller, new { id = id });

            //    const string formFormat = "<form action=\"{0}\" method=\"post\" onsubmit=\"return confirmDelete()\">";
            //    return string.Format(formFormat, postAction);
            //}
            return null;
        }
         * */
   }
}